package my.mbean.web;

import my.mbean.MBeanService;
import my.mbean.util.Response;
import my.mbean.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * MBean Controller.
 /mbean/bean/{beanName}
 /mbean/bean/{beanName}/method/{methodName}
 /mbean/bean/{beanName}/property/{propertyName}
 /mbean/static/
 /mbean/search/{beanNameLike}
 /mbean/
 /mbean/change
 /mbean/invoke
 * Created by xnat on 17/5/6.
 */
public class MBeanController {
    public static final String PARAME_CONTEXTID     = "contextId";
    public static final String PARAME_PROPERTY_NAME = "propertyName";
    public static final String PARAME_METHOD_NAME   = "methodName";
    public static final String PARAME_BEAN_NAME     = "beanName";
    public static final String PARAME_NEWVALUE      = "newValue";
    public static final String PARAME_TYPE_NAME     = "typeName";

    protected final Logger log = LoggerFactory.getLogger(getClass());

    @Resource
    private ApplicationContext  ctx;
    @Resource
    private MBeanService        beansService;
    private Map<String, String> beanViewMap;


    public MBeanController() {
        beanViewMap = new HashMap<>();
    }

    @GetMapping(path = {"", "/"})
    String index(Model model) {
        List<Class<?>> types = beansService.getTypeList();
        model.addAttribute("types",
                Utils.toJsonStr(Utils.toMap(types, c -> c.getSimpleName(), c -> c.getName()))
        );
        if (!types.isEmpty()) {
            if (types.get(0).isAnnotation()) {
                model.addAttribute("beansOfType", Utils.toJsonStr(ctx.getBeanNamesForAnnotation((Class<? extends Annotation>) types.get(0))));
            } else {
                model.addAttribute("beansOfType", Utils.toJsonStr(ctx.getBeansOfType(types.get(0)).keySet()));
            }
        }
        return "index";
    }


    @GetMapping("/bean/{beanName}")
    String browseBean(@PathVariable("beanName") String pBeanName, @RequestParam Map<String, Object> pParams, Model model) {
        String contextId = (String) pParams.get(PARAME_CONTEXTID);
        String templateName = beanViewMap.get(pBeanName);
        Object beanVO = beansService.buildBeanVO(pBeanName, contextId);
        Utils.extractPropertiesToMapValueToJsonStr(beanVO, model);
        if (Utils.isBlank(templateName)) templateName = "bean";
        return templateName;
    }

    @GetMapping("/search/{beanNameLike}")
    String searchPage(@PathVariable("beanNameLike") String beanNameLike, Model model) {
        model.addAttribute("beans", Utils.toJsonStr(beansService.searchBeans(beanNameLike)));
        model.addAttribute("kw", beanNameLike);
        return "search";
    }

    @PostMapping("/change")
    @ResponseBody
    public Response change(@RequestParam Map<String, Object> pParams) {
        log.debug("change(): params: {}", pParams);
        String contextId = (String) pParams.get(PARAME_CONTEXTID);
        String propertyName = (String) pParams.get(PARAME_PROPERTY_NAME);
        String beanName = (String) pParams.get(PARAME_BEAN_NAME);
        String newValue = (String) pParams.get(PARAME_NEWVALUE);
        Response result = beansService.changeProperty(propertyName, beanName, contextId, newValue);
        return result;
    }


    @PostMapping("/invoke")
    @ResponseBody
    public Response invoke(@RequestParam Map<String, Object> pParams)  {
        log.debug("invoke(): params: {}", pParams);
        String methodName = (String) pParams.get(PARAME_METHOD_NAME);
        String beanName = (String) pParams.get(PARAME_BEAN_NAME);
        String contextId = (String) pParams.get(PARAME_CONTEXTID);
        Response result = beansService.invokeMethod(methodName, beanName, contextId);
        return result;
    }

    @GetMapping("/bean/{beanName}/property/{propertyName}")
    String browseBeanProperty(
            @PathVariable("beanName") String pBeanName,
            @PathVariable("propertyName") String propertyName,
            @RequestParam Map<String, Object> pParams,
            Model model
    ) {
        String contextId = (String) pParams.get(PARAME_CONTEXTID);
        Object propertyVO = beansService.buildPropertyVO(propertyName, pBeanName, contextId);
        Utils.extractPropertiesToMapValueToJsonStr(propertyVO, model);
        return "property";
    }

    @GetMapping("/bean/{beanName}/method/{methodName}")
    String browseBeanMethod(
            @PathVariable("beanName") String pBeanName,
            @PathVariable("methodName") String methodName,
            @RequestParam Map<String, Object> pParams,
            Model model
    ) {
        String contextId = (String) pParams.get(PARAME_CONTEXTID);
        model.addAllAttributes(beansService.buildMethodInfo(methodName, pBeanName, contextId));
        return "method";
    }


}
